namespace C1.Win.C1FlexGrid
{
    using C1.Win.C1FlexGrid.Util;
    using C1.Win.C1FlexGrid.Util.Styles;
    using System;
    using System.Collections;
    using System.Drawing;
    using System.Globalization;
    using System.Runtime.CompilerServices;
    using System.Runtime.InteropServices;

    internal class GridModel
    {
        internal Image _buttonImage;
        internal string _clipSeparators;
        internal ColumnCollection _cols;
        internal string _comboList;
        internal GridDataSource _dataSource;
        internal Size _defCellSize;
        internal bool _designMode;
        internal string _editMask;
        internal Column _mouseSortCol;
        internal bool _redraw;
        internal RowCollection _rows;
        internal GridSelHandler _selHandler;
        internal CellStyleCollection _styles;
        internal SubtotalPositionEnum _subtotPos;
        internal bool _transparent;
        internal GridTree _tree;

        internal event GridChangedEventHandler OnGridChanged;

        internal GridModel() : this(50, 10, 1, 1)
        {
        }

        internal GridModel(int rows, int cols, int fixedRows, int fixedCols)
        {
            this._redraw = true;
            this._clipSeparators = "\t\r";
            this._defCellSize = new Size(0x4b, 0x12);
            this._dataSource = new GridDataSource();
            this._selHandler = new GridSelHandler(this);
            this._tree = new GridTree(this);
            this._styles = new CellStyleCollection(this);
            this._subtotPos = SubtotalPositionEnum.AboveData;
            this._cols = new ColumnCollection(this, cols, fixedCols, this._defCellSize.Width);
            this._rows = new RowCollection(this, rows, fixedRows, this._defCellSize.Height);
            this.NotifyViews(GridChangedTypeEnum.LayoutChanged);
        }

        internal double Aggregate(AggregateEnum function, CellRange rg, AggregateFlags flags)
        {
            switch (function)
            {
                case AggregateEnum.None:
                case AggregateEnum.Clear:
                case AggregateEnum.Percent:
                    throw new ArgumentException("Invalid function for Aggregate.");
            }
            int topRow = rg.TopRow;
            int bottomRow = rg.BottomRow;
            int leftCol = rg.LeftCol;
            int rightCol = rg.RightCol;
            if ((leftCol < 0) || (rightCol < 0))
            {
                return 0.0;
            }
            GridTally tally = new GridTally();
            bool flag = false;
            if ((topRow < 0) || (bottomRow < 0))
            {
                topRow = this._rows.Fixed;
                bottomRow = this._rows.Count - 1;
                flag = true;
            }
            bool flag2 = (flags & AggregateFlags.ExcludeNodes) != AggregateFlags.None;
            bool flag3 = (flags & AggregateFlags.AggregateDates) != AggregateFlags.None;
            for (int i = topRow; i <= bottomRow; i++)
            {
                if ((!flag || this._rows[i].Selected) && (!flag2 || !this._rows[i].IsNode))
                {
                    for (int j = leftCol; j <= rightCol; j++)
                    {
                        if (flag3)
                        {
                            object data = this.GetData(i, j);
                            if (data is DateTime)
                            {
                                DateTime time = (DateTime) data;
                                tally.Tally((double) time.Ticks);
                            }
                        }
                        else
                        {
                            tally.Tally(this.GetData(i, j));
                        }
                    }
                }
            }
            return tally.Value(function);
        }

        internal void AssertNotBound()
        {
            if (this.IsDataBound())
            {
                this._dataSource.ThrowInvalidAction();
            }
        }

        internal int CheckNodeChildren(int row, int level)
        {
            int num = 0;
            if (this._subtotPos == SubtotalPositionEnum.AboveData)
            {
                if (row >= (this._rows.Count - 1))
                {
                    return 0;
                }
                if (!this._rows[row + 1].IsNode)
                {
                    num |= 1;
                }
            }
            else
            {
                if (row <= this._rows.Fixed)
                {
                    return 0;
                }
                if (!this._rows[row - 1].IsNode)
                {
                    num |= 1;
                }
            }
            bool flag1 = this._rows[row].IsNode;
            return num;
        }

        internal void Clear(ClearFlags flags, CellRange rg)
        {
            rg.Normalize();
            for (int i = rg.r1; i <= rg.r2; i++)
            {
                for (int j = rg.c1; j <= rg.c2; j++)
                {
                    this.ClearCell(i, j, flags);
                }
            }
            this.NotifyViews(GridChangedTypeEnum.GridChanged);
        }

        internal void ClearCell(int row, int col, ClearFlags clear)
        {
            if ((clear & ClearFlags.Content) != 0)
            {
                this.SetData(row, col, null, false);
                this.SetCellImage(row, col, null);
                this.SetCellCheck(row, col, CheckEnum.None);
            }
            if ((clear & ClearFlags.UserData) != 0)
            {
                this.SetCellUserData(row, col, null);
            }
            if ((clear & ClearFlags.Style) != 0)
            {
                this.SetCellStyle(row, col, null);
            }
        }

        internal virtual Style ComposeCustomStyle(Style sBase, int row, int col)
        {
            Style cellStyle = this.GetCellStyle(row, col);
            Style style2 = (row >= this._rows.Fixed) ? this._cols[col]._style : this._cols[col]._styleFixed;
            Style style3 = (col >= this._cols.Fixed) ? this._rows[row]._style : this._rows[row]._styleFixed;
            if (style3 != null)
            {
                sBase = style3.SetParent(sBase, false);
            }
            if (style2 != null)
            {
                sBase = style2.SetParent(sBase, false);
            }
            if (cellStyle != null)
            {
                sBase = cellStyle.SetParent(sBase, false);
            }
            if (cellStyle != null)
            {
                return cellStyle;
            }
            if (style2 != null)
            {
                return style2;
            }
            if (style3 == null)
            {
                return sBase;
            }
            return style3;
        }

        internal virtual int FindRow(object objFind, int rowStart, int col, bool wrap)
        {
            int num;
            for (num = rowStart; num < this._rows.Count; num++)
            {
                if (Types.Compare(objFind, this.GetData(num, col)) == 0)
                {
                    return num;
                }
            }
            if (wrap)
            {
                for (num = this._rows.Fixed; num < rowStart; num++)
                {
                    if (Types.Compare(objFind, this.GetData(num, col)) == 0)
                    {
                        return num;
                    }
                }
            }
            return -1;
        }

        internal virtual int FindRow(string strFind, int rowStart, int col, bool caseSensitive, bool fullMatch, bool wrap)
        {
            string dataDisplay;
            int num;
            if ((strFind == null) || (strFind.Length == 0))
            {
                return rowStart;
            }
            int length = strFind.Length;
            bool ignoreCase = !caseSensitive;
            for (num = rowStart; num < this._rows.Count; num++)
            {
                dataDisplay = this.GetDataDisplay(num, col);
                if (((dataDisplay != null) && (!fullMatch || (dataDisplay.Length == length))) && (string.Compare(strFind, 0, dataDisplay, 0, length, ignoreCase) == 0))
                {
                    return num;
                }
            }
            if (wrap)
            {
                for (num = this._rows.Fixed; num < rowStart; num++)
                {
                    dataDisplay = this.GetDataDisplay(num, col);
                    if (((dataDisplay != null) && (!fullMatch || (dataDisplay.Length == length))) && (string.Compare(strFind, 0, dataDisplay, 0, length, ignoreCase) == 0))
                    {
                        return num;
                    }
                }
            }
            return -1;
        }

        internal virtual CheckEnum GetCellCheck(int row, int col)
        {
            if (this.ShowValueAsCheck(row, col))
            {
                object obj2 = Types.Coerce(this.GetData(row, col), typeof(bool));
                if ((obj2 != null) && !obj2.Equals(false))
                {
                    return CheckEnum.Checked;
                }
                return CheckEnum.Unchecked;
            }
            CellInfo info = this.GetCellInfo(row, col, false);
            if (info == null)
            {
                return CheckEnum.None;
            }
            return info._check;
        }

        internal string GetCellComboList(int row, int col)
        {
            if (this._cols[col]._comboList != null)
            {
                return this._cols[col]._comboList;
            }
            if (this._rows[row]._comboList != null)
            {
                return this._rows[row]._comboList;
            }
            return this._comboList;
        }

        internal IDictionary GetCellDataMap(int row, int col)
        {
            if (this._cols[col]._dataMap != null)
            {
                return this._cols[col]._dataMap;
            }
            if (this._rows[row]._dataMap != null)
            {
                return this._rows[row]._dataMap;
            }
            return null;
        }

        internal Type GetCellDataType(int row, int col)
        {
            Type type = this._cols[col]._dataType;
            if (type == null)
            {
                type = this._rows[row]._dataType;
            }
            return type;
        }

        internal string GetCellEditMask(int row, int col)
        {
            if (this._cols[col]._editMask != null)
            {
                return this._cols[col]._editMask;
            }
            if (this._rows[row]._editMask != null)
            {
                return this._rows[row]._editMask;
            }
            return this._editMask;
        }

        internal string GetCellFormat(int row, int col)
        {
            string str = this._cols[col]._format;
            if (str == null)
            {
                str = this._rows[row]._format;
            }
            return str;
        }

        internal virtual Image GetCellImage(int row, int col)
        {
            CellInfo info = this.GetCellInfo(row, col, false);
            if (info == null)
            {
                return null;
            }
            return info._image;
        }

        internal Image GetCellImageFromMap(int row, int col)
        {
            if ((row < this._rows.Fixed) || (col < this._cols.Fixed))
            {
                return null;
            }
            IDictionary cellImageMap = this.GetCellImageMap(row, col);
            if (cellImageMap == null)
            {
                return null;
            }
            object data = this.GetData(row, col);
            if ((data != null) && cellImageMap.Contains(data))
            {
                return (Image) cellImageMap[data];
            }
            return (Image) cellImageMap[string.Empty];
        }

        internal IDictionary GetCellImageMap(int row, int col)
        {
            if (this._cols[col]._imageMap != null)
            {
                return this._cols[col]._imageMap;
            }
            if (this._rows[row]._imageMap != null)
            {
                return this._rows[row]._imageMap;
            }
            return null;
        }

        internal bool GetCellImageWithText(int row, int col)
        {
            if (this._cols[col]._imageMap != null)
            {
                return this._cols[col].ImageAndText;
            }
            return ((this._rows[row]._imageMap != null) && this._rows[row].ImageAndText);
        }

        internal virtual CellInfo GetCellInfo(int row, int col, bool create)
        {
            int num = this._cols[col]._dataIndex;
            ArrayList list = this._rows[row]._cellInfo;
            if (((list != null) && (num < list.Count)) && (list[num] != null))
            {
                return (CellInfo) list[num];
            }
            if (!create)
            {
                return null;
            }
            if (list == null)
            {
                list = new ArrayList(this._cols.Count);
                this._rows[row]._cellInfo = list;
            }
            if (list.Capacity < this._cols.Count)
            {
                list.Capacity = this._cols.Count;
            }
            while (list.Count <= num)
            {
                list.Add(null);
            }
            CellInfo info = new CellInfo();
            list[num] = info;
            return info;
        }

        internal virtual Rectangle GetCellRect(int row, int col)
        {
            Rectangle rectangle = new Rectangle();
            rectangle.X = this._cols[col].Left;
            rectangle.Y = this._rows[row].Top;
            rectangle.Width = this._cols[col].WidthDisplay;
            rectangle.Height = this._rows[row].HeightDisplay;
            return rectangle;
        }

        internal virtual Style GetCellStyle(int row, int col)
        {
            CellInfo info = this.GetCellInfo(row, col, false);
            if (info == null)
            {
                return null;
            }
            return info._style;
        }

        internal virtual object GetCellUserData(int row, int col)
        {
            CellInfo info = this.GetCellInfo(row, col, false);
            if (info == null)
            {
                return null;
            }
            return info._userData;
        }

        internal string GetClipRange(CellRange rg, bool sysSep)
        {
            string str = sysSep ? "\r\n" : this.GetClipSeparator(true, sysSep).ToString();
            char clipSeparator = this.GetClipSeparator(false, sysSep);
            rg.Normalize();
            string str2 = string.Empty;
            for (int i = rg.r1; i <= rg.r2; i++)
            {
                if (i > rg.r1)
                {
                    str2 = str2 + str;
                }
                for (int j = rg.c1; j <= rg.c2; j++)
                {
                    if (j > rg.c1)
                    {
                        str2 = str2 + clipSeparator;
                    }
                    str2 = str2 + this.GetDataDisplay(i, j);
                }
            }
            return str2;
        }

        internal string GetClipSelRows(bool sysSep)
        {
            string str = sysSep ? "\r\n" : this.GetClipSeparator(true, sysSep).ToString();
            char clipSeparator = this.GetClipSeparator(false, sysSep);
            string str2 = string.Empty;
            for (int i = 0; i < this._rows.Count; i++)
            {
                if (this._rows[i].Selected)
                {
                    if (str2.Length > 0)
                    {
                        str2 = str2 + str;
                    }
                    for (int j = this._cols.Fixed; j < this._cols.Count; j++)
                    {
                        if (j > this._cols.Fixed)
                        {
                            str2 = str2 + clipSeparator;
                        }
                        str2 = str2 + this.GetDataDisplay(i, j);
                    }
                }
            }
            return str2;
        }

        internal char GetClipSeparator(bool row, bool sysSep)
        {
            if (!sysSep)
            {
                return this._clipSeparators[row ? 1 : 0];
            }
            if (!row)
            {
                return '\t';
            }
            return '\r';
        }

        internal virtual object GetData(int row, int col)
        {
            if ((this.IsDataBound() && !this.IsCellFixed(row, col)) && !this._rows[row].IsNode)
            {
                return this._dataSource.GetData(row, col);
            }
            int num = this._cols[col]._dataIndex;
            ArrayList list = this._rows[row]._cellData;
            if ((list != null) && (num < list.Count))
            {
                return list[num];
            }
            return null;
        }

        internal virtual string GetDataDisplay(int row, int col)
        {
            string str2 = string.Empty;
            object data = this.GetData(row, col);
            if (data == null)
            {
                return string.Empty;
            }
            bool flag = this.IsCellFixed(row, col);
            if (((this.IsDataBound() && !flag) && (!this._rows[row].IsNode && (data.GetType() != this._cols[col].DataType))) && ((this._cols[col].DataType != null) && this._cols[col].DataType.IsEnum))
            {
                return this._dataSource.ConvertToString(data, col);
            }
            IDictionary cellDataMap = this.GetCellDataMap(row, col);
            if ((cellDataMap != null) && cellDataMap.Contains(data))
            {
                return cellDataMap[data].ToString();
            }
            string format = flag ? null : this.GetCellFormat(row, col);
            if ((format == null) || (format.Length == 0))
            {
                return data.ToString();
            }
            try
            {
                if ((data is bool) && (format.IndexOf(";") > -1))
                {
                    return format.Split(new char[] { ';' })[((bool) data) ? 0 : 1];
                }
                if (!(data is IFormattable))
                {
                    return data.ToString();
                }
                str2 = ((IFormattable) data).ToString(format, CultureInfo.CurrentCulture);
            }
            catch
            {
            }
            return str2;
        }

        internal virtual string GetDataDisplay(int row, int col, out Image img, out CheckEnum chk)
        {
            chk = this.GetCellCheck(row, col);
            img = this.GetCellImage(row, col);
            if ((img == null) && (this.GetCellDataType(row, col) == typeof(Image)))
            {
                img = this.GetData(row, col) as Image;
                if (img != null)
                {
                    return null;
                }
            }
            if (img == null)
            {
                img = this.GetCellImageFromMap(row, col);
                if ((img != null) && !this.GetCellImageWithText(row, col))
                {
                    return string.Empty;
                }
            }
            return this.GetDataDisplay(row, col);
        }

        internal string GetDataMember()
        {
            return this._dataSource.GetDataMember().BindingMember;
        }

        internal object GetDataSource()
        {
            return this._dataSource.GetDataSource();
        }

        internal Style GetStyle(CellStyleEnum s)
        {
            return this._styles[s]._style;
        }

        internal virtual Style GetStyleDisplay(int row, int col)
        {
            Style sBase = this.IsCellFixed(row, col) ? this.GetStyle(CellStyleEnum.Fixed) : (this.IsCellFrozen(row, col) ? this.GetStyle(CellStyleEnum.Frozen) : ((((row - this._rows.Fixed) % 2) == 0) ? this.GetStyle(CellStyleEnum.Alternate) : this.GetStyle(CellStyleEnum.Normal)));
            return this.ComposeCustomStyle(sBase, row, col);
        }

        private int InsertSubtotalRow(AggregateEnum function, int level, int groupFrom, int groupTo, int totalOn, string caption, int top, int bot, double grandTotal)
        {
            object data = null;
            bool flag2;
            if (function != AggregateEnum.None)
            {
                CellRange rg = new CellRange(this, top, totalOn, bot, totalOn);
                bool flag = this._cols[totalOn].DataType == typeof(DateTime);
                AggregateFlags excludeNodes = AggregateFlags.ExcludeNodes;
                if (flag)
                {
                    excludeNodes |= AggregateFlags.AggregateDates;
                }
                if (function == AggregateEnum.Percent)
                {
                    data = (grandTotal != 0.0) ? ((this.Aggregate(AggregateEnum.Sum, rg, excludeNodes) / grandTotal) * 100.0) : 0.0;
                }
                else
                {
                    data = this.Aggregate(function, rg, excludeNodes);
                    if (flag)
                    {
                        switch (function)
                        {
                            case AggregateEnum.Average:
                            case AggregateEnum.Max:
                            case AggregateEnum.Min:
                                data = new DateTime((long) ((double) data));
                                goto Label_00B8;
                        }
                    }
                }
            }
        Label_00B8:
            flag2 = this._subtotPos == SubtotalPositionEnum.AboveData;
            int index = 0;
            if (flag2)
            {
                for (index = top; ((index > this._rows.Fixed) && this._rows[index - 1].IsNode) && (this._rows[index - 1]._nodeLevel >= level); index--)
                {
                }
            }
            else
            {
                index = bot + 1;
                while (((index < (this._rows.Count - 1)) && this._rows[index + 1].IsNode) && (this._rows[index + 1]._nodeLevel >= level))
                {
                    index++;
                }
            }
            bool flag3 = ((index < this._rows.Count) && this._rows[index].IsNode) && (this._rows[index]._nodeLevel == level);
            if (!flag3)
            {
                Row row = this._rows.InsertInternal(index, false, true);
                row._nodeLevel = (short) level;
                int num2 = level;
                if (num2 < -1)
                {
                    num2 = -1;
                }
                if (num2 > 5)
                {
                    num2 = 5;
                }
                row.Style = this._styles[9 + num2];
            }
            if (data != null)
            {
                this.SetData(index, totalOn, data, false);
            }
            if (!flag3)
            {
                int num3 = index;
                if (!flag2)
                {
                    while ((num3 > this._rows.Fixed) && this._rows[num3].IsNode)
                    {
                        num3--;
                    }
                }
                else
                {
                    while ((num3 < (this._rows.Count - 1)) && this._rows[num3].IsNode)
                    {
                        num3++;
                    }
                }
                if (caption == null)
                {
                    if (groupFrom > -1)
                    {
                        for (int i = groupFrom; i <= groupTo; i++)
                        {
                            this.SetData(index, i, this.GetData(num3, i), false);
                        }
                    }
                }
                else if (!this.IsBadCol(this._tree.Column))
                {
                    if (groupFrom > -1)
                    {
                        if (caption.IndexOf("{0}") > -1)
                        {
                            caption = string.Format(CultureInfo.CurrentCulture, caption, new object[] { this.GetDataDisplay(num3, groupTo) });
                        }
                        else if (caption.IndexOf("{0:") > -1)
                        {
                            caption = string.Format(CultureInfo.CurrentCulture, caption, new object[] { this.GetData(num3, groupTo) });
                        }
                    }
                    this.SetData(index, this._tree.Column, caption, false);
                }
            }
            if (!flag3)
            {
                return (bot + 1);
            }
            return bot;
        }

        internal bool IsBadCol(int col)
        {
            if (col >= 0)
            {
                return (col >= this._cols.Count);
            }
            return true;
        }

        internal bool IsBadRow(int row)
        {
            if (row >= 0)
            {
                return (row >= this._rows.Count);
            }
            return true;
        }

        internal bool IsBadRowCol(int row, int col)
        {
            if (!this.IsBadRow(row))
            {
                return this.IsBadCol(col);
            }
            return true;
        }

        internal bool IsCellCursor(int row, int col)
        {
            return this._selHandler.IsCellCursor(row, col);
        }

        internal bool IsCellFixed(int row, int col)
        {
            if (!this._rows.IsFixed(row))
            {
                return this._cols.IsFixed(col);
            }
            return true;
        }

        internal bool IsCellFrozen(int row, int col)
        {
            if (!this._rows.IsFrozen(row))
            {
                return this._cols.IsFrozen(col);
            }
            return true;
        }

        internal bool IsCellSelected(int row, int col)
        {
            return this._selHandler.IsCellSelected(row, col);
        }

        internal bool IsDataBound()
        {
            return this._dataSource.IsDataBound();
        }

        internal virtual void NotifyViews(GridChangedTypeEnum action)
        {
            this.NotifyViews(action, -1, -1, -1, -1);
        }

        internal virtual void NotifyViews(GridChangedTypeEnum action, CellRange rg)
        {
            this.NotifyViews(action, rg.r1, rg.c1, rg.r2, rg.c2);
        }

        internal virtual void NotifyViews(GridChangedTypeEnum action, int row, int col)
        {
            this.NotifyViews(action, row, col, -1, -1);
        }

        internal virtual void NotifyViews(GridChangedTypeEnum action, int r1, int c1, int r2, int c2)
        {
            bool flag = false;
            switch (action)
            {
                case GridChangedTypeEnum.RowMoved:
                case GridChangedTypeEnum.RowAdded:
                case GridChangedTypeEnum.RowRemoved:
                case GridChangedTypeEnum.ColMoved:
                case GridChangedTypeEnum.ColAdded:
                case GridChangedTypeEnum.ColRemoved:
                    flag = true;
                    break;

                case GridChangedTypeEnum.LayoutChanged:
                    this._selHandler._range = new CellRange(this, -2, -2);
                    flag = true;
                    break;
            }
            if (flag)
            {
                this._selHandler.Validate();
            }
            if (this.IsDataBound() && (action == GridChangedTypeEnum.AfterSelChange))
            {
                this._dataSource.UpdateCursor();
            }
            if (this.OnGridChanged != null)
            {
                this.OnGridChanged(this, new GridChangedEventArgs(action, r1, c1, r2, c2));
            }
        }

        internal void OnStyleChanged(object sender, StyleEventArgs e)
        {
            this._transparent = false;
            foreach (CellStyle style in (IEnumerable) this._styles)
            {
                if (style.BackColor.A != 0xff)
                {
                    this._transparent = true;
                    break;
                }
            }
            this.NotifyViews(GridChangedTypeEnum.RepaintGrid);
        }

        internal void RefreshData(C1FlexGridBase view, bool force)
        {
            this._dataSource.RefreshData(view, force);
        }

        internal virtual void SetCellCheck(int row, int col, CheckEnum check)
        {
            if (this.ShowValueAsCheck(row, col))
            {
                bool data = (check == CheckEnum.Checked) || (check == CheckEnum.TSChecked);
                this.SetData(row, col, data);
            }
            else
            {
                CellInfo info = this.GetCellInfo(row, col, check != CheckEnum.None);
                if (info != null)
                {
                    info._check = check;
                    this.NotifyViews(GridChangedTypeEnum.RepaintRange, row, col);
                }
            }
        }

        internal virtual void SetCellImage(int row, int col, Image img)
        {
            CellInfo info = this.GetCellInfo(row, col, img != null);
            if (info != null)
            {
                info._image = img;
                this.NotifyViews(GridChangedTypeEnum.RepaintRange, row, col);
            }
        }

        internal virtual void SetCellStyle(int row, int col, Style style)
        {
            CellInfo info = this.GetCellInfo(row, col, style != null);
            if (info != null)
            {
                info._style = style;
                this.NotifyViews(GridChangedTypeEnum.RepaintRange, row, col);
            }
        }

        internal virtual void SetCellUserData(int row, int col, object o)
        {
            CellInfo info = this.GetCellInfo(row, col, o != null);
            if (info != null)
            {
                info._userData = o;
            }
        }

        internal Size SetClipRange(CellRange rg, string s, bool sysSep)
        {
            rg.Normalize();
            char clipSeparator = this.GetClipSeparator(true, sysSep);
            char ch2 = this.GetClipSeparator(false, sysSep);
            Size size = new Size(0, 0);
            string[] strArray = s.Split(new char[] { clipSeparator });
            for (int i = 0; (i < strArray.Length) && ((rg.r1 + i) <= rg.r2); i++)
            {
                string str = strArray[i];
                if (((clipSeparator == '\r') && (str.Length > 0)) && (str[0] == '\n'))
                {
                    str = str.Substring(1);
                }
                if ((sysSep && (str.Length == 0)) && (i == (strArray.Length - 1)))
                {
                    return size;
                }
                size.Height++;
                string[] strArray2 = str.Split(new char[] { ch2 });
                for (int j = 0; (j < strArray2.Length) && ((rg.c1 + j) <= rg.c2); j++)
                {
                    this.SetData(rg.r1 + i, rg.c1 + j, strArray2[j], true);
                    if ((j + 1) > size.Width)
                    {
                        size.Width = j + 1;
                    }
                }
            }
            return size;
        }

        internal virtual bool SetData(int row, int col, object data)
        {
            return this.SetData(row, col, data, true);
        }

        internal virtual bool SetData(int row, int col, object data, bool coerce)
        {
            bool flag = this.IsCellFixed(row, col);
            if ((this.IsDataBound() && !flag) && !this._rows[row].IsNode)
            {
                if (!this._dataSource.SetData(row, col, data))
                {
                    return false;
                }
                this.NotifyViews(GridChangedTypeEnum.RepaintCell, row, col);
                return true;
            }
            if ((coerce && !flag) && (data != null))
            {
                data = Types.Coerce(data, this.GetCellDataType(row, col));
                if (data == null)
                {
                    return false;
                }
            }
            int num = this._cols[col]._dataIndex;
            ArrayList list = this._rows[row]._cellData;
            if (list == null)
            {
                list = new ArrayList(this._cols.Count);
                this._rows[row]._cellData = list;
            }
            if (list.Capacity < this._cols.Count)
            {
                list.Capacity = this._cols.Count;
            }
            while (list.Count <= num)
            {
                list.Add(null);
            }
            list[num] = data;
            this.NotifyViews(GridChangedTypeEnum.RepaintCell, row, col);
            return true;
        }

        internal void SetDataBinding(C1FlexGridBase view, object dataSource, string dataMember)
        {
            this._dataSource.SetDataBinding(view, dataSource, dataMember);
        }

        internal void SetDataMember(C1FlexGridBase view, string newVal)
        {
            this._dataSource.SetDataMember(view, newVal);
        }

        internal void SetDataSource(C1FlexGridBase view, object newVal)
        {
            this._dataSource.SetDataSource(view, newVal);
        }

        internal virtual void ShowSortAt(SortFlags order, int col)
        {
            this._mouseSortCol = null;
            if (!this.IsBadCol(col))
            {
                this._mouseSortCol = this._cols[col];
                if (order != SortFlags.UseColSort)
                {
                    this._mouseSortCol.Sort = order;
                }
            }
            this.NotifyViews(GridChangedTypeEnum.RepaintRange, 0, -1, 0, -1);
        }

        internal bool ShowValueAsCheck(int row, int col)
        {
            if (this.IsCellFixed(row, col))
            {
                return false;
            }
            if (this.GetCellDataType(row, col) != typeof(bool))
            {
                return false;
            }
            if (this.GetCellDataMap(row, col) != null)
            {
                return false;
            }
            if (this.GetCellFormat(row, col) != null)
            {
                return false;
            }
            return true;
        }

        internal virtual void Sort(SortFlags order, CellRange rg)
        {
            if (this.IsDataBound())
            {
                this._dataSource.Sort(order, rg.c1, rg.c2);
                return;
            }
            CellRange range = this._selHandler._range;
            bool flag = rg.Equals(this._selHandler._range);
            rg.Normalize();
            GridRowComparer comparer = new GridRowComparer(this, order, rg.c1, rg.c2);
            for (int i = rg.r1; i <= rg.r2; i++)
            {
                this._rows[i]._index = i;
            }
            ArrayList list = (ArrayList) this._rows._items.Clone();
            int index = rg.r1;
        Label_00D1:
            while (index <= rg.r2)
            {
                if (!this._rows[index].IsNode)
                {
                    break;
                }
                index++;
            }
            int num3 = index;
            while (num3 <= (rg.r2 - 1))
            {
                if (this._rows[num3 + 1].IsNode)
                {
                    break;
                }
                num3++;
            }
            if (index <= rg.r2)
            {
                if (num3 > index)
                {
                    list.Sort(index, (num3 - index) + 1, comparer);
                }
                index = num3 + 1;
                goto Label_00D1;
            }
            this._rows._items = list;
            if (flag)
            {
                this._selHandler.SaveRange(range);
            }
            this._rows.SetDirty();
            this.NotifyViews(GridChangedTypeEnum.RowMoved);
        }

        internal virtual void Sort(int index, int count, IComparer compare)
        {
            ArrayList list = (ArrayList) this._rows._items.Clone();
            list.Sort(index, count, compare);
            this._rows._items = list;
            this._rows.SetDirty();
            this.NotifyViews(GridChangedTypeEnum.RowMoved);
        }

        internal void Subtotal(AggregateEnum function, int level, int groupFrom, int groupTo, int totalOn, string caption)
        {
            bool redraw = this.Redraw;
            this.Redraw = false;
            try
            {
                this.SubtotalInternal(function, level, groupFrom, groupTo, totalOn, caption);
            }
            finally
            {
                this.Redraw = redraw;
            }
        }

        internal void SubtotalInternal(AggregateEnum function, int level, int groupFrom, int groupTo, int totalOn, string caption)
        {
            int num;
            if (function == AggregateEnum.Clear)
            {
                for (num = this._rows.Fixed; num < this._rows.Count; num++)
                {
                    if (this._rows[num].IsNode)
                    {
                        this._rows.RemoveInternal(num, false);
                        num--;
                    }
                }
            }
            else
            {
                if (((this.IsBadCol(groupFrom) || this.IsBadCol(groupTo)) || (groupFrom > groupTo)) && ((groupFrom != -1) || (groupTo != -1)))
                {
                    throw new ArgumentException("Invalid parameters 'groupFrom', 'groupTo' in call to Subtotal method.");
                }
                if ((function != AggregateEnum.None) && this.IsBadCol(totalOn))
                {
                    throw new ArgumentException("Invalid parameter 'totalOn' in call to Subtotal method.");
                }
                double grandTotal = 0.0;
                if (((function == AggregateEnum.Percent) && (totalOn >= 0)) && (totalOn < this._cols.Count))
                {
                    CellRange rg = new CellRange(this, this._rows.Fixed, totalOn, this._rows.Count - 1, totalOn);
                    grandTotal = this.Aggregate(AggregateEnum.Sum, rg, AggregateFlags.ExcludeNodes);
                }
                int top = -1;
                int row = -1;
                for (num = this._rows.Fixed; num < this._rows.Count; num++)
                {
                    if (this._rows[num].IsNode)
                    {
                        continue;
                    }
                    bool flag = false;
                    if ((groupFrom == -1) && (groupTo == -1))
                    {
                        if (num == this._rows.Fixed)
                        {
                            top = this._rows.Fixed;
                            row = this._rows.Count - 1;
                            flag = true;
                        }
                    }
                    else if ((row > -1) && (row != num))
                    {
                        for (int i = groupFrom; i <= groupTo; i++)
                        {
                            object data = this.GetData(num, i);
                            object obj3 = this.GetData(row, i);
                            if (Types.Compare(data, obj3) != 0)
                            {
                                flag = true;
                                break;
                            }
                        }
                    }
                    if (flag)
                    {
                        num = this.InsertSubtotalRow(function, level, groupFrom, groupTo, totalOn, caption, top, row, grandTotal);
                        top = row = -1;
                    }
                    else
                    {
                        if (top < 0)
                        {
                            top = num;
                        }
                        row = num;
                    }
                }
                if (row >= 0)
                {
                    this.InsertSubtotalRow(function, level, groupFrom, groupTo, totalOn, caption, top, row, grandTotal);
                }
            }
        }

        internal Image ButtonImage
        {
            get
            {
                return this._buttonImage;
            }
            set
            {
                this._buttonImage = value;
                this.NotifyViews(GridChangedTypeEnum.RepaintGrid);
            }
        }

        internal bool Redraw
        {
            get
            {
                return this._redraw;
            }
            set
            {
                if (this._redraw != value)
                {
                    this._redraw = value;
                    if (this._redraw)
                    {
                        this._selHandler.Validate();
                        this.NotifyViews(GridChangedTypeEnum.GridChanged);
                    }
                }
            }
        }

        internal SubtotalPositionEnum SubtotalPosition
        {
            get
            {
                return this._subtotPos;
            }
            set
            {
                if (this._subtotPos != value)
                {
                    this.Subtotal(AggregateEnum.Clear, 0, 0, 0, 0, null);
                    this._subtotPos = value;
                }
            }
        }
    }
}

